///PHILOTES Source Code.  (C)2012 PhiloLabs
#pragma once

#ifndef _Codec_H__
#define _Codec_H__

#include "OgrePrerequisites.h"
#include "OgreSharedPtr.h"
#include "OgreDataStream.h"
#include "OgreIteratorWrappers.h"
#include "OgreStringVector.h"
#include "core/exception.h"

namespace Ogre {
	
	

    
	class _OgreExport Codec : public MemAlloc_General
    {
    protected:
        typedef map< String, Codec* >::type CodecList; 
        
        static CodecList msMapCodecs;

    public:
        class _OgrePrivate CodecData : public MemAlloc_General
        {
        public:
            virtual ~CodecData() {}

            
            virtual String dataType() const { return "CodecData"; }
        };
        typedef SharedPtr<CodecData> CodecDataPtr;

        typedef ConstMapIterator<CodecList> CodecIterator;

    public:
    	virtual ~Codec();
    	
        
        static void registerCodec( Codec *pCodec )
        {
			CodecList::iterator i = msMapCodecs.find(pCodec->getType());
			if (i != msMapCodecs.end())
				PHILO_EXCEPT(Exception::ERR_DUPLICATE_ITEM, 
					pCodec->getType() + " already has a registered codec. ", __FUNCTION__);

            msMapCodecs[pCodec->getType()] = pCodec;
        }

		
		static bool isCodecRegistered( const String& codecType )
		{
			return msMapCodecs.find(codecType) != msMapCodecs.end();
		}

		
        static void unRegisterCodec( Codec *pCodec )
        {
            msMapCodecs.erase(pCodec->getType());
        }

        
        static CodecIterator getCodecIterator(void)
        {
            return CodecIterator(msMapCodecs.begin(), msMapCodecs.end());
        }

        
        static StringVector getExtensions(void);

        
        static Codec* getCodec(const String& extension);

		
		static Codec* getCodec(char *magicNumberPtr, size_t maxbytes);

        
        virtual DataStreamPtr code(MemoryDataStreamPtr& input, CodecDataPtr& pData) const = 0;
        
        virtual void codeToFile(MemoryDataStreamPtr& input, const String& outFileName, CodecDataPtr& pData) const = 0;

        /// Result of a decoding; both a decoded data stream and CodecData metadata
        typedef std::pair<MemoryDataStreamPtr, CodecDataPtr> DecodeResult;
        
        virtual DecodeResult decode(DataStreamPtr& input) const = 0;

        
        virtual String getType() const = 0;

        
        virtual String getDataType() const = 0;

		
		virtual bool magicNumberMatch(const char *magicNumberPtr, size_t maxbytes) const 
		{ return !magicNumberToFileExt(magicNumberPtr, maxbytes).empty(); }
		
		virtual String magicNumberToFileExt(const char *magicNumberPtr, size_t maxbytes) const = 0;
    };
	
	

} // namespace

#endif
